package com.atguigu.gmall.mq.receiver;

import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @author: 封捷
 * @create-date: 2022/9/9 11:06
 */
@Slf4j
@Component
@Configuration
public class ConfirmReceiver {

    @SneakyThrows
    @RabbitListener(
            // bindings 属性：配置交换机和队列直接的路由关系
        bindings = @QueueBinding(

                // @Queue 注解的 durable 属性设置为 true，表示队列要持久化
                // @Queue 注解的 autoDelete 属性设置为 false，表示队列关闭自动删除
                value = @Queue(value = "queue.brother_gui", durable = "true", autoDelete = "false"),

                // @Exchange 注解的 durable 属性设置为 true，表示队列要持久化
                // @Exchange 注解的 autoDelete 属性设置为 false，表示队列关闭自动删除
                exchange = @Exchange(value = "exchange.brother_gui", durable = "true", autoDelete = "false"),

                // 设置当前绑定关系中对应的路由键
                key = {"routingKey.brother_gui"}
        )
    )
    public void process(
            // 接收到的消息
            Message message,

            // 当前所属的频道，可以用来做手动确认
            Channel channel) {

        try {

            // ※为了测试失败的情况，人为制造一个异常
            System.out.println(10 / 0);

            // 字节码数组形式的消息体
            byte[] messageBodyBytes = message.getBody();

            // 把消息体封装为字符串
            String messageBody = new String(messageBodyBytes);

            // 打印当前接收到的消息
            log.info("接收到的消息：" + messageBody);

            // 获取消息的投递标签
            long deliveryTag = message.getMessageProperties().getDeliveryTag();

            // 设定是否批量操作
            boolean multiple = false;

            // 手动返回 ACK 确认消息
            channel.basicAck(deliveryTag, multiple);

        } catch (Exception e) {
            e.printStackTrace();

            // 获取消息是否被消费的标识数据
            Boolean redelivered = message.getMessageProperties().getRedelivered();

            if (redelivered) {
                log.info("[消息接收端]消息重复投递，拒绝消息");

                // 如果消息是被重复投递的，那么我们拒绝这个消息
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            } else {
                log.info("[消息接收端]手动返回 NACK 确认，消息放回队列");
                // 手动返回 NACK 确认，把消息放回队列
                // 第三个参数设置为 true，标识放回队列
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);

            }

        }

    }

}
